-------------------------------------------------------------------------------
-- Title      : Ref. clk period quantizer
-- Project    : Frequency Locked Loop (FLL) - IIS/DZ
-------------------------------------------------------------------------------
-- File       : FLL_clk_period_quantizer.vhd
-- Author     : David Bellasi <bellasi@ee.ethz.ch>
-- Company    : Integrated Systems Laboratory, ETH Zurich
-- Created    : 2016-10-18
-------------------------------------------------------------------------------
-- Description: Counts the positive edges of the the DCO output clock that
--              occur wthin one reference clock period. Thus, the function
--              is a time-to-digital converter that produces a quantized
--              version of the  reference clock period, where the quantization
--              step is the period of the DCO output clock.
--              The implementation is a simple counter clocked by the DCO
--              output clock. The counter runs for one ref. clock period.
--              The counting starts at the falling edge of the ref clock
--              in order to obtain a shorter delay between measurement and
--              loop update.
--
-------------------------------------------------------------------------------
-- Copyright 2018 ETH Zurich and University of Bologna.
-- Copyright and related rights are licensed under the Solderpad Hardware
-- License, Version 0.51 (the "License"); you may not use this file except in
-- compliance with the License.  You may obtain a copy of the License at
-- http:--solderpad.org/licenses/SHL-0.51. Unless required by applicable law
-- or agreed to in writing, software, hardware and materials distributed under
-- this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
-- CONDITIONS OF ANY KIND, either express or implied. See the License for the
-- specific language governing permissions and limitations under the License.
-------------------------------------------------------------------------------
-- Revisions  :
-- Date        Version  Author              Description
-- 2016-10-18  3.0      bellasid            ported to tsmc55lp
-- 2017-01-27  3.1      muheim              change it to tech independens
-------------------------------------------------------------------------------

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity FLL_clk_period_quantizer is
  generic(
    COUNTER_WIDTH : natural := 14
    );
  port(
    DCOClk_CI  : in  std_logic;         -- clk generated by the VCO/DCO
    RefClk_CI  : in  std_logic;         -- reference clk
    Rst_RBI    : in  std_logic;         -- hard reset
    En_SI      : in  std_logic;
    Counter_DO : out std_logic_vector(COUNTER_WIDTH-1 downto 0)  -- counter value, send back to control
    );
end FLL_clk_period_quantizer;

architecture rtl of FLL_clk_period_quantizer is

  ----------------------------------------------------------------------
  -- Signals/contants declarations -------------------------------------
  ----------------------------------------------------------------------

  signal QuantCnt_DP, QuantCnt_DN         : unsigned(COUNTER_WIDTH-1 downto 0);
  signal QuantCntKeep_DP, QuantCntKeep_DN : unsigned(COUNTER_WIDTH-1 downto 0);

  signal RefEdge_D              : std_logic;
  signal RefEdge_DP, RefEdge_DN : std_logic_vector(3 downto 0);


begin

  --------------------------------------------------------------------------------
  -- detect falling edge on the ref clk
  --------------------------------------------------------------------------------

  RefEdge_DN <= RefEdge_DP(2 downto 0) & RefClk_CI;

  process (DCOClk_CI, Rst_RBI)
  begin
    if Rst_RBI = '0' then
      RefEdge_DP <= (others => '0');
    elsif DCOClk_CI = '1' and DCOClk_CI'event then
      if En_SI = '1' then
        RefEdge_DP <= RefEdge_DN;
      end if;
    end if;
  end process;

  RefEdge_D <= (not RefEdge_DP(2)) and RefEdge_DP(3);


  --------------------------------------------------------------------------------
  -- start counting the dco cycles between two falling ref edges
  --------------------------------------------------------------------------------

  process (QuantCnt_DP, RefEdge_D)
  begin
    QuantCnt_DN <= QuantCnt_DP+1;
    if QuantCnt_DP = 2**(QuantCnt_DP'length)-1 then  -- avoid counter overflow
      QuantCnt_DN <= (others => '1');
    end if;
    if RefEdge_D = '1' then
      QuantCnt_DN <= (others => '0');
    end if;
  end process;

  QuantCntKeep_DN <= QuantCnt_DP;

  process (DCOClk_CI, Rst_RBI)
  begin
    if Rst_RBI = '0' then
      QuantCnt_DP     <= (others => '0');
      QuantCntKeep_DP <= (others => '0');
    elsif DCOClk_CI = '1' and DCOClk_CI'event then  -- max freq ~ 1 GHz
      if En_SI = '1' then
        QuantCnt_DP <= QuantCnt_DN;
      end if;
      if En_SI = '1' and RefEdge_D = '1' then
        QuantCntKeep_DP <= QuantCntKeep_DN;
      end if;
    end if;
  end process;


  -- final counter value (can savely be sampled in the ref clock domain at the
  -- rising edge of the ref clock since the counter is updated at the falling
  -- edge of the ref clock)
  Counter_DO <= std_logic_vector(QuantCntKeep_DP);


end rtl;
